package wordEvo.daemon;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

import whipstaff.tools.IOHelper;
import whipstaff.tools.OutputLog;
import whipstaff.wordevo.data.Result;
import whipstaff.wordevo.database.Database;

/**
 * @author Jim Buck, Whipstaff Productions
 * @since August 22, 2011
 * @updated August 23, 2011
 */
public class EvoUpdate {

	private OutputLog log;
	
	private final String dbPath = "database";
	private final String dbName = "wordevo.db";
	
	private final String userName = "wordevo";
	private final String password = "watchmaker";
	private String url = "//whip.dyndns-server.com/wordevo";
	
	private List<Result> resultList;
	
	private File statsSheet;
	
	private Connection connection;
	private Database dbase2;
	
	public void begin() {
		this.initDaemon();
		this.loadFiles();
		this.updateDB();
		this.destroyDaemon();
	}
	
	// Initializes the variables and loads the objects.
	private void initDaemon() {		
		this.log = new OutputLog("./logs", "daemonlog.html", true);
		
		this.resultList = new Vector<Result>();
		this.dbase2 = null;
		
		this.connectDB();
	}
	
	private void connectDB() {		
		try {
			this.connection = null;
			Class.forName ("com.mysql.jdbc.Driver").newInstance ();
			this.connection = DriverManager.getConnection (url, userName, password);
	        System.out.println ("Database connection established");
		} catch (Exception e) {
			this.log.printerr("There was an error connecting to the database.");
			this.log.printerr(IOHelper.stackTraceToString(e));
		}
        
	}
	
	// Loads the necessary data files.
	private void loadFiles() {
		this.loadAllResults();
	}
		
	// Loads the database from file into memory.
	private void loadDB() {		
		try {
			this.dbase2 = (Database) IOHelper.loadFromFile(new File(this.dbPath, this.dbName));
			
		} catch (FileNotFoundException e) {
			System.err.println("Database not found. Creating new...");
			this.dbase2 = new Database("WordEvoDB");
		} catch (IOException e) {
			System.err.println("ERROR: There was problem writing to file.");
			e.printStackTrace();
			System.exit(1);
		} catch (ClassNotFoundException e) {
			System.err.println("ERROR: There was a problem translating the file.");
			e.printStackTrace();
			System.exit(1);
		}
	}
	// Checks for files and loads them if found.
	private void loadAllResults() {
		List<File> listOfFiles = IOHelper.getFileList("./results", ".results");
		for(File res : listOfFiles) {
			Result result = this.loadResult(res);
			this.resultList.add(result);
		}
	}
	// Loads the object file into memory.
	private Result loadResult(File file) {
		Result result= null;
		try {
			InputStream buffer = new BufferedInputStream(new FileInputStream(file));
			
		    ObjectInputStream input = new ObjectInputStream( buffer );
		    result = (Result) input.readObject();
		    input.close();
		} catch (FileNotFoundException e) {
			this.log.printerr("No results found!");
		} catch (IOException e) {
			this.log.printerr("ERROR: There was problem writing to file.");
			this.log.printerr(IOHelper.stackTraceToString(e));
			System.exit(1);
		} catch (ClassNotFoundException e) {
			this.log.printerr("ERROR: There was a problem translating the file.");
			this.log.printerr(IOHelper.stackTraceToString(e));
			this.log.printerr("Exiting...");
			System.exit(1);
		}
		
		return result;
	}
	
	// Adds the results to the DB and generates a new fact sheet.
	private void updateDB() {		
		this.backupDB();
		this.insertResults();
		this.updateStats();
		this.saveDBtoFile();
	}

	// Creates a copy of the database with the day of the week in the filename.
	private void backupDB() {
		try {
			IOHelper.saveToFile(this.dbase2, new File("./database" , "backup_" + 
								Calendar.getInstance().get(Calendar.DAY_OF_WEEK) + ".db.bkup"));
		} catch (FileNotFoundException e) {
			this.log.printerr(e.getMessage());
			this.log.printerr("There was an error creating the file. Moving on...");
		} catch (IOException e) {
			this.log.printerr(e.getMessage());
			this.log.printerr("There was an error saving to file. Moving on...");
		}
	}
	// Adds the results to the database.
	private void insertResults() {
		for(Result result: this.resultList) {
			this.dbase2.addData(result);
		}
	}

	// Updates the statistics page.
	private void updateStats() {
		this.archiveStatSheet();
		this.createNewStatSheet();
	}

	
	private void archiveStatSheet() {
		// TODO: Compress and move folder to archives. 
		//SimHelper.saveToFile(this.statsSheet, SimHelper.getNewFileName("./stats/archive", "", ".html"));
	}

	private void createNewStatSheet() {
		// TODO: Create complex file/folder output.
	}

	// Saves the new DB over the old one.
	private void saveDBtoFile() {
		File file = new File(this.dbPath, this.dbName);
		try {
			IOHelper.saveToFile(this.dbase2, file);
			this.log.println("Database saved to file: " + file.getPath());
		} catch (FileNotFoundException e) {
			this.log.printerr("There was an error creating the file.");
			this.log.printerr(e.getMessage() + ". (" + file.getAbsolutePath() + ")");
			this.log.printerr(IOHelper.stackTraceToString(e));
		} catch (IOException e) {
			this.log.printerr("There was an IO Exception.");
			this.log.printerr(e.getMessage() + ". (" + file.getAbsolutePath() + ")");
			this.log.printerr(IOHelper.stackTraceToString(e));
		}
	}

	// Closes the streams and properly exits the daemon.
	private void destroyDaemon() {
		this.resultList = null;
		
		System.gc();
	}
}
